#include "StdAfx.h"
#include "GViewer.h"
#include "GraphicsPlatform.h"

CGViewer::CGViewer(CGraphicsPlatform* pParent)
: m_eOperateType(eNoneOperate),
  m_bOperating(false),
  m_pParent(pParent),
  m_pArrowPreview(NULL),
  m_pCSGraphics(NULL)
{
}

CGViewer::~CGViewer(void)
{
	delete m_pArrowPreview;
	m_pArrowPreview = NULL;

	delete m_pCSGraphics;
	m_pCSGraphics = NULL;
}

void CGViewer::Fit(CGBox& oBox)
{
	CVec min = oBox.GetMin();
	CVec max = oBox.GetMax();

	CVec target = CVec(max[0], max[1], (max[2] + min[2])/2);
	CVec eye = CVec(min[0], min[1], (max[2] + min[2])/2);

	CVec V = eye - target;
	eye = eye + V * V.Length() * 4;

	m_oCamera.SetTarget(target);
	m_oCamera.SetEye(eye);

	m_dSmallDistance = (0.05*(max - min).Length());

	m_box = oBox;
}

void CGViewer::SetViewRange(int iWidth, int iHeight)
{
	m_iViewWidth = iWidth;
	m_iViewHeight = iHeight;
}

void CGViewer::GetViewRange(int& iWidth, int& iHeight)
{
	iWidth = m_iViewWidth;
	iHeight = m_iViewHeight;
}

void CGViewer::StartRotate(int iPtX, int iPtY)
{
	m_iViewPtX = iPtX;
	m_iViewPtY = iPtY;
	SetOperateType(eRotate);
	m_bOperating = true;
}

void CGViewer::StartPan(int iPtX, int iPtY)
{
	m_iViewPtX = iPtX;
	m_iViewPtY = iPtY;
	SetOperateType(ePan);
	m_bOperating = true;
}

void CGViewer::StopOperate()
{
	SetOperateType(eNoneOperate);
	m_bOperating = false;
}

void CGViewer::OnRotate(int iPtX, int iPtY)
{
	Rotating(iPtX - m_iViewPtX, iPtY - m_iViewPtY);
}

void CGViewer::OnPan(int iPtX, int iPtY)
{
	CVec V1;
	ViewToModelSpace(m_iViewPtX, m_iViewPtY, V1);

	CVec V2;
	ViewToModelSpace(iPtX, iPtY, V2);

	CVec V = V1 ^ V2;
	V.Identify();
	double dCrossAngle = V1.CrossAngle(V2);

	CVec A = m_oCamera.m_UpDir;
	CVec C = m_oCamera.m_Eye - m_oCamera.m_Target;
	double len = C.Length();
	C.Identify();

	A.RotateBy(V, -dCrossAngle);
	C.RotateBy(V, -dCrossAngle);
	m_oCamera.m_Target = m_oCamera.m_Eye - C * len;
	m_oCamera.m_UpDir = A;
}

void CGViewer::OnZoom(double dScale)
{
	CVec C = m_oCamera.m_Eye - m_oCamera.m_Target;
	double len = C.Length();
	len = len * dScale;
	C.Identify();

	m_oCamera.m_Eye = m_oCamera.m_Target + C * len;
}

void CGViewer::Rotating(int iDeltaX, int iDeltaY)
{
	double dAngle1 = iDeltaX * 4 * SK_PI / m_iViewWidth;
	double dAngle2 = iDeltaY * 4 * SK_PI / m_iViewHeight;

	CVec A = m_oCamera.m_UpDir;
	CVec C = m_oCamera.m_Eye - m_oCamera.m_Target;
	CVec B = A ^ C;

	// Step1, C rotate A as Angle1
	C.RotateBy(A, dAngle1);

	// Step2, B rotate A as Angle1
	B.RotateBy(A, dAngle1);

	// Step3, C rotate B as Angle2
	C.RotateBy(B, dAngle2);
	
	// Step4, A rotate B as Angle2
	A.RotateBy(B, dAngle2);

	// Step5, eye = target + C
	m_oCamera.m_Eye = m_oCamera.m_Target + C;

	// step6, reset up as A
	m_oCamera.m_UpDir = A;
}

void CGViewer::ViewToModelSpace(int iPtX, int iPtY, CVec& pt)
{
	m_pParent->Translate2DTo3D(iPtX, iPtY, pt);
}

void CGViewer::ModelSpaceToView(const CVec& pt, int& iPtX, int& iPtY)
{
	m_pParent->Translate3DTo2D(pt, iPtX, iPtY);
}

void CGViewer::Update(int iPtX, int iPtY)
{
	m_iViewPtX = iPtX;
	m_iViewPtY = iPtY;
}

void CGViewer::GetScreenPt(int& iViewPtX, int& iViewPtY)
{
	iViewPtX = m_iViewPtX;
	iViewPtY = m_iViewPtY;
}

CCoordinateSystemGraphics* CGViewer::GetCSGraphics()
{
	if (m_pCSGraphics == NULL)
	{
		m_pCSGraphics = new CCoordinateSystemGraphics(this);
	}
	return m_pCSGraphics;
}

CLineArrowGraphics* CGViewer::GetPreviewObject()
{
	if (m_pArrowPreview == NULL)
	{
		m_pArrowPreview = new CLineArrowGraphics(this);
	}
	return m_pArrowPreview;
}

bool CGViewer::Reset()
{
	m_oCamera.Reset();
	m_oSelectSet.Clear();
	m_oHighLightSet.Clear();

	return true;
}